package com.wxzhou.wangzhuan.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.redis.datasource.ReactiveRedisDataSource;
import io.quarkus.redis.datasource.keys.ReactiveKeyCommands;
import io.quarkus.redis.datasource.value.ReactiveValueCommands;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;

/**
 * redis全局通用服务对象
 */
@ApplicationScoped
public class RedisService {
    @Inject
    ReactiveRedisDataSource reactiveRedisDataSource;

    @Inject
    ObjectMapper objectMapper;

    private final ReactiveValueCommands<String, String> valueCommands;
    private final ReactiveKeyCommands<String> keyCommands;

    private static final Duration DEFAULT_EXPIRE = Duration.ofMinutes(30);

    public RedisService(ReactiveRedisDataSource redisDataSource) {
        this.valueCommands = redisDataSource.value(String.class);
        this.keyCommands = redisDataSource.key(String.class);
    }

    public Uni<Void> addList(String redisKey, List<?> datas) {
        return addList(redisKey, DEFAULT_EXPIRE.getSeconds(), datas);
    }

        /**
         * 将泛型List加入到redis中
         *
         * @param redisKey Redis键
         * @param ttl      过期时间（秒）
         * @param datas    要存储的数据列表
         * @return Void
         */
    public Uni<Void> addList(String redisKey, long ttl, List<?> datas) {
        // 校验 datas 不为空且 size > 0 才加入到缓存
        if (datas == null || datas.isEmpty()) {
            return Uni.createFrom().voidItem();
        }
        
        return Uni.createFrom().item(datas)
                .onItem().transformToUni(list -> {
                    try {
                        // 将List序列化为JSON字符串
                        String jsonData = objectMapper.writeValueAsString(list);
                        // 存储到Redis
                        return valueCommands.set(redisKey, jsonData)
                                .chain(() -> {
                                    // 设置过期时间
                                    if (ttl > 0) {
                                        return keyCommands.expire(redisKey, ttl);
                                    }
                                    return Uni.createFrom().voidItem();
                                });
                    } catch (Exception e) {
                        return Uni.createFrom().failure(e);
                    }
                })
                .onItem().ignore().andContinueWithNull();
    }

    /**
     * 从Redis中获取泛型List
     *
     * @param redisKey Redis键
     * @param clazz    List中元素的类型
     * @param <T>      泛型类型
     * @return 数据列表
     */
    public <T> Uni<List<T>> getList(String redisKey, Class<T> clazz) {
        // 先检查键是否存在
        return keyCommands.exists(redisKey)
                .onItem().transformToUni(exists -> {
                    // 如果键不存在，直接返回空列表
                    if (!exists) {
                        return Uni.createFrom().item((List<T>) new ArrayList<>());
                    }
                    
                    // 键存在，获取数据
                    return valueCommands.get(redisKey)
                            .onItem().transformToUni(jsonData -> {
                                if (jsonData == null || jsonData.isEmpty()) {
                                    return Uni.createFrom().item((List<T>) new ArrayList<T>());
                                }
                                try {
                                    // 将JSON字符串反序列化为List
                                    List<T> result = objectMapper.readValue(jsonData,
                                            objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
                                    return Uni.createFrom().item(result);
                                } catch (Exception e) {
                                    return Uni.createFrom().failure(e);
                                }
                            });
                })
                .onFailure().recoverWithItem(() -> (List<T>) new ArrayList<>());
    }
}
